package com.chen.posp;

import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.chen.posp.enums.PosManufacturer;
import com.chen.posp.exception.MacCheckInvalidException;
import com.chen.posp.exception.MacCreateInvalidException;
import com.chen.posp.exception.POSISO8583Exception;

import shaded.org.apache.commons.lang3.StringUtils;


public class PosRequestReceiveReturnServiceImpl implements PosRequestReceiveReturnService {

	private Log log = LogFactory.getLog(PosRequestReceiveReturnServiceImpl.class);
//	private TrxTypeDictService trxTypeDictService;
//	private PosService posService;
	private Posiso8583Factory posiso8583Factory;

	public UnionPayParam Decoding(byte[] requestBytes, UnionPayParam unionPayParamTemp) throws MacCreateInvalidException, MacCheckInvalidException {

		byte[] requestByte = new byte[requestBytes.length - 2]; // 去掉两位报文长度
		int contenlen = requestBytes.length - 2;
		System.arraycopy(requestBytes, 2, requestByte, 0, contenlen);
		int messageLen = requestBytes.length;
		int offset = 0;

		UnionPayParam unionPayParam = new UnionPayParam();

		// 检查TPUD
		if (contenlen < Constant.LEN_POS_TPUD) {
			log.info("POSISO8583 Decoding parse message fail, data len less than TPUD's length");
			throw new POSISO8583Exception(POSISO8583Exception.ERROR_RESPONSE_ITEM_TPUD);
		}

		byte[] tpudtype = new byte[Constant.LEN_POS_TPUD];
		System.arraycopy(requestByte, offset, tpudtype, 0, Constant.LEN_POS_TPUD);
		String tpdu = ISO8583Utile.bcd2String(tpudtype, false);
		unionPayParam.setTPDU(tpdu);

		contenlen -= Constant.LEN_POS_TPUD;
		offset += Constant.LEN_POS_TPUD;

		byte[] lri = new byte[Constant.LEN_POS_LRI]; // 拨号POS标识
		System.arraycopy(requestByte, offset, lri, 0, Constant.LEN_POS_LRI);

		byte[] l2 = new byte[2];
		System.arraycopy(requestByte, offset + 2, l2, 0, 2);

		String lriTemp = new String(lri);
		log.info("the POS message head  lriTemp [" + lriTemp + "] ");
		boolean lriFlag = false;
		if (Constant.CONTENT_POS_LRI.equals(lriTemp)) {
			lriFlag = true;
			log.info("go into pos_lri success! contenlen[" + contenlen + "]");
			int byteStart = offset;
			byte[] lrilength = new byte[2];
			System.arraycopy(requestByte, byteStart + 3, lrilength, 0, 2); // 长度
			byteStart += Constant.LEN_POS_LRI;
			byteStart += 2;  // 略过2字节的长度域
			byte[] sourcePhonebyte = new byte[Constant.LEN_POS_PHONE];
			System.arraycopy(requestByte, byteStart, sourcePhonebyte, 0, Constant.LEN_POS_PHONE);
			byteStart += Constant.LEN_POS_PHONE;
			byte[] destPhonebyte = new byte[Constant.LEN_POS_PHONE];
			System.arraycopy(requestByte, byteStart, destPhonebyte, 0, Constant.LEN_POS_PHONE);
			byteStart += Constant.LEN_POS_PHONE;
			byteStart += 4;  // 略过4个字节的分隔符和长度域
			byte[] nodebyte = new byte[Constant.LEN_POS_NODE];
			System.arraycopy(requestByte, byteStart, nodebyte, 0, Constant.LEN_POS_NODE);
			byteStart += Constant.LEN_POS_NODE;
			offset += 33;  // 略过33个字节的拨号POS特殊报文域
			contenlen -= 33;
			// 处理来电电话和被叫电话
			String callPhoneNo = ISO8583Utile.bcd2String(sourcePhonebyte, false);
			String servicePhoneNo = ISO8583Utile.bcd2String(destPhonebyte, false);
			unionPayParam.setCallPhoneNo(callPhoneNo);
			unionPayParam.setServicePhoneNo(servicePhoneNo);

		}

		// 检查报文头
		if (contenlen < Constant.LEN_POS_Message) {
			log.info("POSISO8583 Decoding parse message fail, data len less than CERTIFIED VERSION's length");
			throw new POSISO8583Exception(POSISO8583Exception.ERROR_RESPONSE_ITEM_TPUD);
		}
		byte[] versiontype = new byte[Constant.LEN_POS_Message];
		System.arraycopy(requestByte, offset, versiontype, 0, Constant.LEN_POS_Message);
		String version = ISO8583Utile.bcd2String(versiontype, false);
		PosManufacturer posManufacturer = (PosManufacturer) Constant.contentMessageMap.get(version); // 报文上送厂商

		contenlen -= Constant.LEN_POS_Message;
		offset += Constant.LEN_POS_Message;

		byte[] decodeingByte = new byte[contenlen];
		System.arraycopy(requestByte, offset, decodeingByte, 0, contenlen);

		Posiso8583 posiso8583 = new CommonPosiso8583(); // 默认
		if (PosManufacturer.HZR.equals(posManufacturer)) {
			posiso8583 = new CommonPosiso8583();
		} else if (PosManufacturer.XDL.equals(posManufacturer) || PosManufacturer.ZT.equals(posManufacturer) || PosManufacturer.ZT.equals(posManufacturer)) {
			//posiso8583 = new CodPosiso8583();
		}

		unionPayParam.setPosManufacturer(posManufacturer);
		unionPayParamTemp.setPosManufacturer(unionPayParam.getPosManufacturer());
		try {
			unionPayParam = (UnionPayParam) posiso8583.Decoding(decodeingByte, contenlen, unionPayParam);
		} catch (POSISO8583Exception e) {
			log.error("", e);
		} 

		String track2data = unionPayParam.getTrack_2_data();

		if (StringUtils.isNotBlank(track2data)) {
			boolean flag = track2data.contains("=");
			if (flag) {// 新格式的会员卡二磁道
				int i = track2data.indexOf("=");
				unionPayParam.setPrimary_acct_num(track2data.substring(0, i)); // 卡号
			} else {
				unionPayParam.setPrimary_acct_num(track2data); // 卡号
			}
		}

		String macString = unionPayParam.getMac();

		// 调用加密机，来验证MAC是否正确

		if (macString != null) {//

			byte[] macInput = null;
			if (lriFlag) {
				macInput = new byte[messageLen - 54]; // 需要做异或的MAC数据
				System.arraycopy(requestBytes, 46, macInput, 0, messageLen - 54);
			} else {
				macInput = new byte[messageLen - 21]; // 需要做异或的MAC数据
				System.arraycopy(requestBytes, 13, macInput, 0, messageLen - 21);
			}
			String makeMacString = ISO8583Utile.getXorString(macInput); // 异或后的十六进制字符串
			
			//联通自助缴费退款,mac源串暂时存放59.2域
			if(Constant.COMMON_UNIONBILLPURCHASEREFUND.equals(unionPayParam.getTrx_source())){
				log.info("unionBillPurchaseRefund , mac check after !");
				try {
					unionPayParam.setNoUse56(makeMacString);
					BeanUtils.copyProperties(unionPayParamTemp, unionPayParam);
					unionPayParamTemp.setPosManufacturer(unionPayParam.getPosManufacturer());
				} catch (IllegalAccessException e1) {
					log.error("unionPayParam copy error! IllegalAccessException",e1);
				} catch (InvocationTargetException e2) {
					log.error("unionPayParam copy error! InvocationTargetException",e2);
				}
				return unionPayParam;
			}
			
			String psopMac = null;
			try {
				long mactime=System.currentTimeMillis();
				//psopMac = EncryptUtils.createMacForPos(PosManufacturer.HZR, unionPayParam.getCard_accptr_termnl_id(), makeMacString);
				mactime=System.currentTimeMillis()-mactime;
				log.info("EncryptUtils.createMacForPos use time:"+mactime+"ms");
			} catch (Exception e) {
				try {
					BeanUtils.copyProperties(unionPayParamTemp, unionPayParam);
					unionPayParamTemp.setPosManufacturer(unionPayParam.getPosManufacturer());
				} catch (IllegalAccessException e1) {
					log.error("unionPayParam copy error! IllegalAccessException", e1);
				} catch (InvocationTargetException e2) {
					log.error("unionPayParam copy error! InvocationTargetException", e2);
				}
				throw new MacCreateInvalidException();
			}

			log.info("POSP Generate MAC: " + psopMac.substring(0, 8));
			log.info("POS MAC(64 field): " + macString);

			if (!macString.equals(psopMac.substring(0, 8))) {// MAC校验不通过
				log.info("POS mac error!");
				try {
					BeanUtils.copyProperties(unionPayParamTemp, unionPayParam);
					unionPayParamTemp.setPosManufacturer(unionPayParam.getPosManufacturer());
				} catch (IllegalAccessException e) {
					log.error("unionPayParam copy error! IllegalAccessException");
				} catch (InvocationTargetException e) {
					log.error("unionPayParam copy error! InvocationTargetException");
				}
				throw new MacCheckInvalidException();
			}
		}

		// unionPayParam.setTrxType(posTrxRequest.getTrxType());
		return unionPayParam;
	}

	public Posiso8583Factory getPosiso8583Factory() {
		return posiso8583Factory;
	}

	public void setPosiso8583Factory(Posiso8583Factory posiso8583Factory) {
		this.posiso8583Factory = posiso8583Factory;
	}

}
